﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SimpleBlog.Infrastructure.Repositories;
using System.Net;
using System.Linq.Expressions;
using SimpleBlog.Models;
using SimpleBlog.ViewModels;
using SimpleBlog.Helpers;
using System.Web.Routing;
using Microsoft.Web.Helpers;
using SimpleBlog.Mvc;

namespace SimpleBlog.Controllers
{
    public class CommentController : Controller
    {
        private const string TempCommentViewModelKey = "__SimpleBlog__CommentViewModel__";

        ICommentRepository _commentRepository;
        IPostRepository _postRepository;
        IConfigurationRepository _configurationRepository;

        public CommentController(ICommentRepository commentRepository, IPostRepository postRepository, IConfigurationRepository configurationRepository)
        {
            _commentRepository = commentRepository;
            _postRepository = postRepository;
            _configurationRepository = configurationRepository;
        }

        public ActionResult Index(int? id, int page = 1, int count = 5)
        {
            if (!id.HasValue || id.Value <= 0)
                throw new HttpException(404, "The has to have a value.");

            if (page < 1 || count < 1)
                throw new HttpException((int)HttpStatusCode.BadRequest, "Page or Count parameter has to be greater than 1.");

            Expression<Func<Comment, bool>> filter = x => x.PublishedIn.PostId == id.Value;
            var comments = _commentRepository.Search(filter, page, count);
            var maxPag = Math.Max((int)Math.Ceiling((double)_commentRepository.Count(filter) / count), 1);

            var model = new CommentListViewModel
            {
                MaxPage = maxPag,
                Page = page,
                Items = comments.Select(x => new CommentViewModel
                    {
                        Item = x,
                        Author = x is UserComment ? ((UserComment)x).Creator.Name : ((AnonymousComment)x).Name,
                        PhotoUrl = x is UserComment ? ((UserComment)x).Creator.PhotoUrl : string.Empty
                    }
                )
            };

            return PartialView(model);
        }

        public ActionResult Create(int? id)
        {
            if (!id.HasValue || id.Value <= 0)
                throw new HttpException(404, "The id has to have a value.");

            CommentCreateViewModel model = null;
            if (TempData.ContainsKey(TempCommentViewModelKey))
            {
                model = TempData[TempCommentViewModelKey] as CommentCreateViewModel;
                this.ModelStateFromTemp();
            }
            else
            {
                model = new CommentCreateViewModel();
            }

            model.CommentPostId = id.Value;
            if (Request.IsAuthenticated)
            {
                model.CommentName = SessionHelper.Authenticated.Login;
                model.CommentEmail = SessionHelper.Authenticated.Email;
            }
            return PartialView(model);
        }

        [HttpPost]
        public ActionResult Create(CommentCreateViewModel viewModel)
        {
            var post = _postRepository.FindById(viewModel.CommentPostId);
            if (post == null)
            {
                throw new HttpException(404, "The post with the especified id not exist");
            }
            if (!string.IsNullOrWhiteSpace(_configurationRepository.ReCaptchaPublicKey) 
                && !string.IsNullOrWhiteSpace(_configurationRepository.ReCaptchaPrivateKey))
            {
                if (!ReCaptcha.Validate(privateKey: _configurationRepository.ReCaptchaPrivateKey))
                {
                    ModelState.AddModelError("ReCaptcha", "ReCaptcha validation failed.");
                }
            }
            if (ModelState.IsValid)
            {
                Comment comment;
                if (Request.IsAuthenticated)
                {
                    comment = new UserComment
                    {
                        Creator = SessionHelper.Authenticated
                    };
                }
                else
                {
                    comment = new AnonymousComment
                    {
                        Name = viewModel.CommentName,
                        Email = viewModel.CommentEmail
                    };
                }
                comment.Created = DateTime.UtcNow;
                comment.Moderated = true;
                comment.Published = true;
                comment.PublishedIn = post;
                comment.Text = HttpUtility.HtmlEncode(viewModel.CommentText).NewLinesToHtml();

                _commentRepository.Add(comment);
                if (comment.CommentId == 0)
                {
                    throw new HttpException(500, "Critical: Error creating Comment.");
                }

                return RedirectToAction("Index", new { controller = "Post", name = post.EncodedTitle });
            }
            //If there are any error in the model, save viewmodel and modelstate
            //and get it in [GET Method]/Comment/Create
            TempData[TempCommentViewModelKey] = viewModel;
            this.ModelStateToTemp();

            return RedirectToAction("Index", new { controller = "Post", name = post.EncodedTitle });
        }
    }
}
